home *** CD-ROM | disk | FTP | other *** search
/ Amiga Tools 3 / Amiga Tools 3.iso / programming / nnn1.35 / src / nnn.c < prev    next >
C/C++ Source or Header  |  1995-08-29  |  20KB  |  689 lines

  1. /*
  2.  * $Id: nnn.c 1.35 1995/08/29 23:50:11 daltern Exp $
  3.  *
  4.  *    Program        nnn
  5.  *    Programmers    Nicholas d'Alterio
  6.  *            Gideon Denby
  7.  *            Ata Etemadi (some of the i/o code)
  8.  *     Date        20/02/95
  9.  *    
  10.  *  Synopis:    This is a a neural network program which uses the 
  11.  *         back propagation alogorithm with a sigmoid activation
  12.  *        function.
  13.  *  Usage:    (brief)
  14.  *        nnn -h                     for help
  15.  *        nnn < conf_file > new_conf_file     training
  16.  *        nnn -g < conf_file > graph_file        training progress graph
  17.  *        nnn -m < conf_file > new_conf_file    for classification
  18.  *
  19.  *  Other Associated Functions:-    NetFeedForward()
  20.  *                    NetBackProp()
  21.  *                    NetTransFunc()
  22.  *                    NetVecRand()
  23.  *                    NetWriteConfig()
  24.  *                    NetExit()
  25.  *                    NetAbort()
  26.  *
  27.  *  $Log: nnn.c $
  28.  * Revision 1.35  1995/08/29  23:50:11  daltern
  29.  * Now exits nicely if CTRL-C aborted, memory deallocated etc.
  30.  * Done using global variables
  31.  *
  32.  * Revision 1.34  1995/08/29  23:15:00  daltern
  33.  * coorect preprocessor symbol for conditional compilation
  34.  *
  35.  * Revision 1.33  1995/08/27  01:54:22  daltern
  36.  * changed way the time between updates is calculated. Also
  37.  * added a couple of extra messages to give better idea of
  38.  * progress in early stages of program.
  39.  *
  40.  * Revision 1.32  1995/08/26  22:16:11  daltern
  41.  * remembered why I didn't have previous change before ! removed change
  42.  *
  43.  * Revision 1.31  1995/08/26  22:12:54  daltern
  44.  * Added message if no arguments are given
  45.  *
  46.  * Revision 1.30  1995/08/26  22:05:43  daltern
  47.  * Added checking for CTRL-C aborts, conditional amiga code
  48.  * Added status messages for monitoring progress of training
  49.  *
  50.  * Revision 1.29  1995/07/11  20:03:47  daltern
  51.  * added ADOS version string
  52.  *
  53.  * Revision 1.28  1995/03/22  01:26:25  daltern
  54.  * Added new extended comments
  55.  *
  56.  * Revision 1.27  1995/03/22  01:04:27  daltern
  57.  * Now expects weights for each layer on separate lines
  58.  *
  59.  * Revision 1.26  1995/03/22  00:34:04  daltern
  60.  * BUGFIX: vectors not read in properly if training continued
  61.  * after previous attempt. Added extra flag to avoid problem
  62.  * Added code simplifying variables
  63.  *
  64.  * Revision 1.25  1995/03/20  23:40:54  daltern
  65.  * Added code for gain factor
  66.  * BUGFIX: bias node on layers above input layer were being changed
  67.  * because used for temp storage. Now reinitialised after each
  68.  * backprop
  69.  *
  70.  * Revision 1.23  1995/03/17  18:13:58  projects
  71.  * Ammended so that weights ending on a bias are ignored
  72.  *
  73.  * Revision 1.22  1995/03/17  17:52:00  projects
  74.  * Made large memory saving by only allocating the array elements
  75.  * that are needed rather than max size. Also improved speed of
  76.  * initialisation and removed max size finding code
  77.  *
  78.  * Revision 1.21  1995/03/16  19:28:54  daltern
  79.  * Added momentum rate to program. Reads in this parameter
  80.  * from config file or accepts it from command line after
  81.  * -m option. Changed the classifying option to -i
  82.  *
  83.  * Revision 1.20  1995/03/16  18:19:51  daltern
  84.  * adjusted biasing so that there is a bias node with a random
  85.  * weights going from it to all other nodes
  86.  *
  87.  * Revision 1.17  1995/03/16  10:35:44  projects
  88.  * Fixed some bad help messages with -h option
  89.  *
  90.  * Revision 1.16  1995/03/14  23:40:14  daltern
  91.  * Removed some wasted assignments
  92.  *
  93.  * Revision 1.15  1995/03/14  22:51:14  daltern
  94.  * Fixed up biasing to enable easy changing from config file
  95.  * commented properly
  96.  *
  97.  */
  98.  
  99. #include "Neural.h"
  100.  
  101.   extern char *version = "$VER: nnn 1.35 (29.08.95) Nicholas d'Alterio";
  102.  
  103. /*
  104.  *   Global variables to enable proper cleanup if the program
  105.  *   is interupted by CTRL-C. They should not be used for any 
  106.  *   other purpose.
  107.  */
  108.  
  109.   NET      *netI_g;
  110.   VECTOR *vecS_g;
  111.   float  **Node_g;
  112.   float  ***Weight_g;
  113.   float  ***Delta_weight_g;
  114.  
  115. main( int argc, char *argv[] )
  116.  
  117. {
  118.  
  119.   int i,j,k;          /* Loop indicies and flags                          */
  120.   int status;
  121.   int mode;           /* FALSE = Training mode, TRUE = Classify mode      */
  122.   int update;
  123.  
  124.   int rateflag;       /* various flags                                    */
  125.   int seedflag;
  126.   int accuflag;
  127.   int vecflag;
  128.   int momflag;
  129.   int graphflag;
  130.   int classflag;
  131.   int accurateflag;
  132.   int gainflag;
  133.   int weightsflag;
  134.  
  135.   int output_nodes;   /* code simplifying variables                       */
  136.   int output_layer;
  137.  
  138.   int class_its;      /* number of iterations is training loop            */
  139.   
  140.   int cur_vec;        /* Current vector number                            */
  141.  
  142.   float learn_rate;   /* Learning rate                                    */
  143.   float seed;         /* Seed for random number generator                 */
  144.   float accuracy;     /* Desired output accuracy                          */
  145.   float mom_fac;      /* momentum factor                                  */
  146.  
  147.   float usr_rate;     /* User supplied command line parameters            */
  148.   float usr_seed;          
  149.   float usr_accuracy; 
  150.   float usr_vec_cor;
  151.   float usr_mom_fac;
  152.   float usr_gain;
  153.  
  154.   float vecs_correct; /* Number of classified vectors                     */
  155.   float per_cor;      /* percentage  " "          ""                      */
  156.   float num_correct;  /* number of vectors meeting accuracy condition     */
  157.   float    result;       /* difference between target and actual output      */
  158.   float gain;         /* gain factor                                      */
  159.   
  160.   float **Node;       /* The nodes                                        */
  161.  
  162.   float ***Weight;    /* the weights between nodes                        */
  163.   float ***Delta_weight;
  164.  
  165.   VECTOR vecS;          /* The vectors to classify or train with            */
  166.  
  167.   NET netI;           /* Information about the net sizes                  */
  168.  
  169.   char text[MAXCHAR];
  170.  
  171. /*==========================================================================*
  172.                        SET UP CTRl-C ABORT FUNCTION
  173.  *==========================================================================*/
  174.  
  175.   if ( signal( SIGINT, (&NetAbort) ) == SIG_ERR ) {
  176.  
  177.     fprintf( stderr, " CRTL-C breaks will not be handled correctly\n" );
  178.  
  179.   }   /* end if */
  180.  
  181. /*==========================================================================*
  182.                         COMMAND LINE PARAMETERS
  183.  *==========================================================================*/
  184.  
  185.   rateflag  = FALSE;
  186.   seedflag  = FALSE;
  187.   accuflag  = FALSE;
  188.   vecflag   = FALSE;
  189.   mode      = FALSE;
  190.   graphflag = FALSE;
  191.   momflag   = FALSE;
  192.   gainflag  = FALSE;
  193.  
  194.   for (i=1; i < argc; i++) {
  195.        if (argv[i][0] == '-') {
  196.            switch (argv[i][1]) {
  197.             case 'r': usr_rate     = atof(argv[++i]); rateflag = TRUE; break;
  198.             case 's': usr_seed     = atof(argv[++i]); seedflag = TRUE; break;
  199.             case 'a': usr_accuracy = atof(argv[++i]); accuflag = TRUE; break;
  200.         case 'c': usr_vec_cor  = atof(argv[++i]); vecflag  = TRUE; break;
  201.             case 'm': usr_mom_fac  = atof(argv[++i]); momflag  = TRUE; break;
  202.         case 'k': usr_gain     = atof(argv[++i]); gainflag = TRUE; break;
  203.             case 'i': mode = TRUE;                                     break;
  204.         case 'g': graphflag = TRUE;                       break;
  205.             case 'h': 
  206.             fprintf(stderr,"Usage\n"); 
  207.             fprintf(stderr,"Training mode:\n");
  208.             fprintf(stderr," %s < configfile.conf > outputfile.conf \n",argv[0]);
  209.             fprintf(stderr,"Classification mode:\n");
  210.             fprintf(stderr," %s -m < configfile.conf > output \n",argv[0]);
  211.             fprintf(stderr,"These command line switches OVERRIDE values in config file:\n"); 
  212.             fprintf(stderr,"-r <rate>    : Learning rate\n"); 
  213.             fprintf(stderr,"-s <seed>    : Seed for random number generator\n"); 
  214.             fprintf(stderr,"-a <accuracy>: Desired accuracy\n"); 
  215.             fprintf(stderr,"-c <%%>       : Desired %% of Vectors correct\n");
  216.         fprintf(stderr,"-m <mom fac> : Momentum factor in range 0-1\n");
  217.         fprintf(stderr,"-k <gain>    : Gain factor\n");
  218.             fprintf(stderr,"-i           : Classify input vectors in config file\n");
  219.             fprintf(stderr,"-g           : Output graph to stdout instead of config file\n"); 
  220.             fprintf(stderr,"-h           : Print this usage information\n"); 
  221.             exit(0);
  222.             default : fprintf(stderr,"Unrecognized option %s [Try -h for Usage]\n",argv[i]); exit(-1);
  223.           }   /* end switch */
  224.        }   /* end if */
  225.   }   /* end for */
  226.  
  227. /*==========================================================================*
  228.                              INITIALISATION
  229.  *==========================================================================*/
  230.  
  231. /*
  232.  *  Read in various network parameters - anything which is not
  233.  *  a number is skipped over.
  234.  */
  235.  
  236.   while (! fscanf (stdin, "%du", &netI.NumLayers)) 
  237.     fscanf (stdin, "%*[^\n]");
  238.   while (! fscanf (stdin, "%fu", &learn_rate)) 
  239.     fscanf (stdin, "%*[^\n]");
  240.   while (! fscanf (stdin, "%fu", &mom_fac)) 
  241.     fscanf (stdin, "%*[^\n]");
  242.   while (! fscanf (stdin, "%fu", &gain)) 
  243.     fscanf (stdin, "%*[^\n]");
  244.   while (! fscanf (stdin, "%fu", &seed)) 
  245.     fscanf (stdin, "%*[^\n]");
  246.   while (! fscanf (stdin, "%fu", &accuracy)) 
  247.     fscanf (stdin, "%*[^\n]");
  248.   while (! fscanf (stdin, "%fu", &vecs_correct)) 
  249.     fscanf (stdin, "%*[^\n]");
  250.  
  251. /*
  252.  *  Replace values with command line supplied values if supplied
  253.  */
  254.  
  255.   if (rateflag == TRUE)
  256.        learn_rate = usr_rate;
  257.   if (seedflag == TRUE)
  258.        seed = usr_seed;
  259.   if (accuflag == TRUE)
  260.        accuracy = usr_accuracy;
  261.   if (vecflag == TRUE)
  262.        vecs_correct = usr_vec_cor;
  263.   if (momflag ==TRUE)
  264.        mom_fac = usr_mom_fac;
  265.   if (gainflag == TRUE)
  266.        gain = usr_gain;
  267.  
  268. /*
  269.  *  Allocate memory for layer size info.
  270.  */
  271.  
  272.   MAKE1D(netI.LayerSize,int,netI.NumLayers);
  273.   netI_g = &netI;
  274.  
  275. /*
  276.  *  Read in delimiter and get layer size info. This determines the
  277.  *  number of nodes in each layer.
  278.  */
  279.  
  280.   fscanf(stdin,"%s",text);
  281.   if(!strcmp(text,DELIMITER[2])) {
  282.  
  283.     for ( i = 0; i < netI.NumLayers; i++ ) {
  284.  
  285.         fscanf(stdin,"%d",&netI.LayerSize[i]);
  286.         fscanf(stdin,"\n");
  287.  
  288.     }   /* end for i */
  289.   
  290.   } else {
  291.  
  292.     fprintf(stderr,"\n No information on net - exiting\n");
  293.     exit(1);
  294.  
  295.   }   /* end if */
  296.     
  297. /*
  298.  *  Allocate memory for Weights, Node etc
  299.  */
  300.  
  301.   MAKE3D(Weight,float,(netI.NumLayers-1),(netI.LayerSize[i]+1),(netI.LayerSize[i+1]+1));
  302.   Weight_g = Weight;
  303.   MAKE3D(Delta_weight,float,(netI.NumLayers-1),(netI.LayerSize[i]+1),(netI.LayerSize[i+1]+1));
  304.   Delta_weight_g = Delta_weight;
  305.   MAKE2D(vecS.InVec,float,MAX_VECS,(netI.LayerSize[0]+1));
  306.   MAKE2D(vecS.OutVec,float,MAX_VECS,(netI.LayerSize[netI.NumLayers-1]+1));
  307.   vecS_g = &vecS;
  308.  
  309. /*
  310.  *  Nodes array is a 2D float array except for the first row, for
  311.  *  which no memory is allocated. This is just kept as a pointer for
  312.  *  the input vector.
  313.  */
  314.  
  315.   Node = (float **)malloc(netI.NumLayers*sizeof(float *));
  316.     for ( i = 1; i < netI.NumLayers; i++ ) 
  317.         Node[i] = (float *)malloc((netI.LayerSize[i]+1)*sizeof(float));
  318.   Node_g = Node;
  319.  
  320. /* 
  321.  *  Read in delimiter to see if a Weights section has been supplied
  322.  */
  323.  
  324.   weightsflag = FALSE;
  325.   fscanf(stdin,"%s",text);
  326.   if (strcmp(text,DELIMITER[1])) { 
  327.  
  328. /*
  329.  *  weightsflag determines wether the #vectors should be read in later 
  330.  *  in the file. Needs to read in if weights are in config file. 
  331.  */
  332.  
  333.     weightsflag = TRUE;
  334.       fprintf(stderr,"\n Using supplied Weights.\n");
  335.  
  336. /*
  337.  *  Read in the Weights from config file. Each line in file is
  338.  *  one layer.
  339.  */
  340.  
  341.     for ( i = 0; i < (netI.NumLayers-1); i++ ) {
  342.         for ( j = 0; j < (netI.LayerSize[i]+1); j++) {
  343.             for ( k = 1; k < (netI.LayerSize[i+1]+1); k++) {
  344.  
  345.                           fscanf(stdin,"%f",&Weight[i][j][k]);
  346.  
  347.             }   /* end for k */
  348.         }   /* end for j */
  349.     }   /* end for i */
  350.  
  351.   } else {  
  352.  
  353. /*
  354.  *  If we are not in training mode warn user and exit.
  355.  */
  356.  
  357.     if (mode == TRUE) {
  358.          fprintf(stderr,"\n To classify vectors Weights MUST be supplied in config file\n");    
  359.          NetExit(&netI,&vecS,Node,Weight,Delta_weight);
  360.     }   /* end if */
  361.  
  362.  
  363. /*
  364.  *  Initialize Weights to small random values since there are no 
  365.  *  stored values.
  366.  */
  367.  
  368.         fprintf(stderr,"\n Initialising Weights using random numbers.\n");
  369.  
  370.       SEED_FUNC((long)(netI.LayerSize[0]*seed) ); /* Choose a seed */
  371.     for ( i = 0; i < (netI.NumLayers-1); i++ ) {
  372.         for ( j = 0; j < (netI.LayerSize[i]+1); j++) {
  373.             for ( k = 0; k < (netI.LayerSize[i+1]+1); k++) {
  374.  
  375.                 SEED_FUNC((long) (seed*RAND_FUNC()));
  376.                           Weight[i][j][k] = RAND_FUNC();
  377.  
  378.             }   /* end for k */
  379.         }   /* end for j */
  380.       }   /* end for i : initialise Weights */
  381.  
  382.   } /* endif #Vectors delimiter */
  383.  
  384.  
  385. /*
  386.  *  Read in the vectors. 
  387.  *  The first value is the bias node. This is followed by the inputs
  388.  *  Finally at the end of the line is the expected output. This should
  389.  *  not present if in classification mode.
  390.  *  The first vectors bias node is the most important since this is used
  391.  *  for the rest of the networks biasing.
  392.  */
  393.  
  394.   if(mode) fscanf(stdin,"%s",text);
  395.   status       = 1;
  396.   vecS.NumVecs = 0;
  397.   do {
  398.       
  399.     for (i=0; i < (netI.LayerSize[0]+1); i++) {
  400.         status = fscanf(stdin,"%f ",&vecS.InVec[vecS.NumVecs][i]);
  401.     }   /* end for i */
  402.  
  403.       if ( !mode ) {
  404.                for (i=0; i < netI.LayerSize[netI.NumLayers-1]; i++) {
  405.                    status = fscanf(stdin,"%f ",&vecS.OutVec[vecS.NumVecs][i]);
  406.                }   /* end for i */
  407.       }   /* end if */
  408.  
  409.   } while (status != EOF && status != 0 && ( ++vecS.NumVecs < MAX_VECS ) );
  410.  
  411. /*
  412.  *  Initialise the previous delta weights to 0 for the momentum factor.
  413.  */
  414.  
  415.   for ( i = 0; i < (netI.NumLayers-1); i++ ) {
  416.     for ( j = 0; j < (netI.LayerSize[i]+1); j++) {
  417.         for ( k = 0; k < (netI.LayerSize[i+1]+1); k++) {
  418.  
  419.                       Delta_weight[i][j][k] = 0.0;
  420.  
  421.         }   /* end for k */
  422.     }   /* end for j */
  423.   }   /* end for i */
  424.  
  425. /*
  426.  *  Set up some code simplifying variables.
  427.  */
  428.  
  429.   output_layer = netI.NumLayers-1;
  430.   output_nodes = netI.LayerSize[output_layer];
  431.  
  432. /*==========================================================================*
  433.                             SET UP FOR BIASES
  434.  *==========================================================================*/
  435.  
  436. /*
  437.  *  Set up biases. Each layer has one bias node index [layer][0] this is 
  438.  *  set to the bias setting for the first vector.
  439.  */
  440.  
  441.   for ( i = 1; i < netI.NumLayers; i++ ) {
  442.     Node[i][0] = vecS.InVec[0][0];
  443.   }   /* end for i */
  444.  
  445. /*
  446.  *+++
  447.  */
  448.  
  449.  if ( mode ) {
  450.  
  451. /*==========================================================================*
  452.                       START MAIN CLASSIFICATION LOOP
  453.  *==========================================================================*/
  454.  
  455. /*
  456.  *  This section uses the previously trained neural network to try and 
  457.  *  decide what the ouputs for a given vector should be.
  458.  *  It feeds forwards each vector through the network and then for
  459.  *  each output node it decides which binary output it should be.
  460.  *  This information is then printed to config file after input and also
  461.  *  to the screen.
  462.  */
  463.  
  464.   fprintf( stderr, "\n Beginning classification\n" );
  465.  
  466.   for ( cur_vec = 0; cur_vec < vecS.NumVecs; cur_vec++ ) {
  467.  
  468. /*  
  469.  *  Make input vector the input nodes.
  470.  */
  471.  
  472.     Node[0] = vecS.InVec[cur_vec];
  473.  
  474. /*
  475.  *  Feed the data through the Neural Network
  476.  */
  477.  
  478.     NetFeedForward(Weight,Node,netI,gain);
  479.  
  480. /*
  481.  *  Loop for each output Node.
  482.  */
  483.  
  484.      for ( i = 0; i < output_nodes; i++ ) {
  485.  
  486. /*
  487.  *  If output node is greater than 0.5 then it is in a high state
  488.  *  otherwise it is in a low state.
  489.  */
  490.  
  491.         if ( Node[output_layer][i+1] >= 0.5 ) {
  492.  
  493.             vecS.OutVec[cur_vec][i] = HIGH_STATE;
  494.  
  495.         } else {
  496.  
  497.             vecS.OutVec[cur_vec][i] = LOW_STATE;
  498.  
  499.         }   /* end if */
  500.  
  501.         fprintf( stderr, " Vector %d Output %d is in state %.1f\n", cur_vec, i, vecS.OutVec[cur_vec][i] );
  502.  
  503.      }   /* end for i : loop over all output Nodes */    
  504.  
  505.   }   /* end for cur_vec */
  506.  
  507. /*==========================================================================*
  508.                           END MAIN CLASSIFICATION LOOP
  509.  *==========================================================================*/
  510.  
  511. /*
  512.  *+++
  513.  */
  514.  
  515.  } else {
  516.  
  517. /*==========================================================================*
  518.                          START OF MAIN TRAINING LOOP
  519.  *==========================================================================*/
  520.  
  521.  
  522. /*
  523.  *  This code is the neural net training loop. In each loop the vectors
  524.  *  have their order randomised. The vectors are then fed forwards in turn 
  525.  *  through the network and the output nodes checked against the target. If
  526.  *  the difference meets the accuracy specified for the % of vectors specified
  527.  *  then the loop finishes, otherwise the errors are back propagated and the
  528.  *  loop begins again. If more than MAX_ITS iterations are carried out without
  529.  *  training completing then the loop is ended in its current state.  
  530.  */
  531.  
  532.   classflag   = FALSE;
  533.   class_its   = 0;
  534.   update      = 0;
  535.  
  536.   fprintf( stderr, "\n Beginning training\n\n" );
  537.  
  538.   while ( !classflag ) {
  539.  
  540. /*
  541.  *  Randomise order of vectors so that the largest possible area
  542.  *  of the error surface during convergence, hopefully avoiding 
  543.  *  local minima.
  544.  */
  545.  
  546.     num_correct = 0;
  547.     NetVecRand( &vecS );
  548.  
  549. /*
  550.  *  Loop over each vector.
  551.  */
  552.  
  553.      for ( cur_vec = 0; cur_vec < vecS.NumVecs; cur_vec++ ) {
  554.  
  555. /*
  556.  *  Make the current input vector the first nodes row then feed
  557.  *  that through the network to get an output.
  558.  */
  559.  
  560.         Node[0] = vecS.InVec[cur_vec];
  561.         NetFeedForward(Weight,Node,netI,gain);
  562.  
  563. /*
  564.  *  Check each output node for accuracy.
  565.  */
  566.  
  567.         for ( i = 0; i < output_nodes; i++ ) {
  568.             result=fabs(vecS.OutVec[cur_vec][i]-Node[output_layer][i+1] );
  569.  
  570. /*
  571.  *  Print graph data if requested.
  572.  */
  573.  
  574.             if (graphflag)fprintf(stdout,"%d\t%f\n",class_its,result);
  575.  
  576.             if ( result < accuracy ) {
  577.                 accurateflag = TRUE;
  578.             } else {
  579.                 accurateflag = FALSE;
  580.             }  /* end if : accuracy check */
  581.         }   /* end for i : accuracy check */
  582.         if ( accurateflag ) num_correct++;
  583.  
  584. /*
  585.  *  Backpropagate the errors to improve the weights.
  586.  */
  587.     
  588.         NetBackProp(Weight,Delta_weight,Node,netI,vecS.OutVec[cur_vec],learn_rate,mom_fac,gain);
  589.  
  590. /*
  591.  *  Reset bias nodes which have been altered during back prop.
  592.  */
  593.  
  594.         for ( i = 1; i < netI.NumLayers; i++ ) {
  595.             Node[i][0] = vecS.InVec[0][0];
  596.           }   /* end for i */
  597.  
  598.      }   /* end for cur_vec : do 1 learning cycle */
  599.  
  600. /*
  601.  *  Calculate the percentage of the vectors num_correct.
  602.  */
  603.  
  604.     per_cor = ( num_correct * 100.0 ) / (float)(vecS.NumVecs);
  605.  
  606.     if ( per_cor >= vecs_correct ) {
  607.         fprintf( stderr,"\n Training complete %3.1f %% of vectors classified correctly.\n", per_cor );
  608.         fprintf( stderr," training took %d iterations to complete\n\n",class_its);
  609.         classflag = TRUE;
  610.     } else {
  611.         classflag = FALSE;
  612.     }   /* end if : check for classification */
  613.  
  614. /*
  615.  *   Print a progress report every USER_UPDATE iterations. Also for amiga
  616.  *   users check if there has been an abort request.
  617.  */
  618.  
  619.     if ( (++update) > USER_UPDATE ) {
  620.  
  621.         fprintf( stderr,"Currently trained to %3.1f %% classification after %d iterations\r",per_cor, class_its );
  622.         fflush( stderr );
  623.         update = 0;
  624.  
  625. #ifdef _AMIGA
  626.  
  627.         chkabort();
  628.  
  629. #endif
  630.  
  631.     }   /* end if */
  632.  
  633. /*
  634.  *  Make sure that the Neural Network is converging to requested
  635.  *  accuracy within a certain number of iterations.
  636.  */
  637.  
  638.     class_its++;
  639.     if ( class_its > MAX_ITS ) { 
  640.         fprintf( stderr,"\n Can't classify to requested level\n" );
  641.         fprintf( stderr," Current classification accuracy is %3.1f %%\n", per_cor );
  642.         classflag = TRUE;
  643.     }  /* end if : stop if too many iterations */
  644.  
  645.   }   /* end while : loop until classified */
  646.  
  647.  }   /* end if : train or classification mode */
  648.  
  649. /*===========================================================================*
  650.                           END OF MAIN TRAINING LOOP
  651.  *===========================================================================*/
  652. /*===========================================================================*
  653.                         SAVE RESULTS AND CLEANUP
  654.  *===========================================================================*/
  655.  
  656. /*
  657.  *  Write out config style to stdout if user has not chosen graph option.
  658.  */
  659.  
  660.   if (!graphflag) {
  661.     NetWriteConfig(netI,vecS,Weight,seed,learn_rate,mom_fac,accuracy,vecs_correct,gain);
  662.   }   /* end if graph flag */
  663.  
  664. /*
  665.  *  Free memory and exit.
  666.  */
  667.  
  668.   NetExit(&netI,&vecS,Node,Weight,Delta_weight);
  669.  
  670. }   /* end program nnn */
  671.  
  672. /*==========================================================================*
  673.                              END OF PROGRAM
  674.  *==========================================================================*/
  675.  
  676.  
  677.  
  678.  
  679.                 
  680.  
  681.  
  682.  
  683.  
  684.  
  685.  
  686.  
  687.  
  688.  
  689.